home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Python / thread_nt.h < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-03  |  8.9 KB  |  329 lines

  1. /* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
  2. /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
  3.  
  4. #include <windows.h>
  5. #include <limits.h>
  6. #include <process.h>
  7.  
  8. typedef struct NRMUTEX {
  9.     LONG   owned ;
  10.     DWORD  thread_id ;
  11.     HANDLE hevent ;
  12. } NRMUTEX, *PNRMUTEX ;
  13.  
  14.  
  15. typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ;
  16.  
  17. /* Sorry mate, but we haven't got InterlockedCompareExchange in Win95! */
  18. static PVOID WINAPI interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand)
  19. {
  20.     static LONG spinlock = 0 ;
  21.     PVOID result ;
  22.     DWORD dwSleep = 0;
  23.  
  24.     /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */
  25.     while(InterlockedExchange(&spinlock, 1))
  26.     {
  27.         // Using Sleep(0) can cause a priority inversion.
  28.         // Sleep(0) only yields the processor if there's
  29.         // another thread of the same priority that's
  30.         // ready to run.  If a high-priority thread is
  31.         // trying to acquire the lock, which is held by
  32.         // a low-priority thread, then the low-priority
  33.         // thread may never get scheduled and hence never
  34.         // free the lock.  NT attempts to avoid priority
  35.         // inversions by temporarily boosting the priority
  36.         // of low-priority runnable threads, but the problem
  37.         // can still occur if there's a medium-priority
  38.         // thread that's always runnable.  If Sleep(1) is used,
  39.         // then the thread unconditionally yields the CPU.  We
  40.         // only do this for the second and subsequent even
  41.         // iterations, since a millisecond is a long time to wait
  42.         // if the thread can be scheduled in again sooner
  43.         // (~100,000 instructions).
  44.         // Avoid priority inversion: 0, 1, 0, 1,...
  45.         Sleep(dwSleep);
  46.         dwSleep = !dwSleep;
  47.     }
  48.     result = *dest ;
  49.     if (result == comperand)
  50.         *dest = exc ;
  51.     /* Release spinlock */
  52.     spinlock = 0 ;
  53.     return result ;
  54. } ;
  55.  
  56. static interlocked_cmp_xchg_t *ixchg ;
  57. BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex)
  58. {
  59.     if (!ixchg)
  60.     {
  61.         /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */
  62.         HANDLE kernel = GetModuleHandle("kernel32.dll") ;
  63.         if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL)
  64.             ixchg = interlocked_cmp_xchg ;
  65.     }
  66.  
  67.     mutex->owned = -1 ;  /* No threads have entered NonRecursiveMutex */
  68.     mutex->thread_id = 0 ;
  69.     mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
  70.     return mutex->hevent != NULL ;    /* TRUE if the mutex is created */
  71. }
  72.  
  73. #define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand)))
  74.  
  75. VOID DeleteNonRecursiveMutex(PNRMUTEX mutex)
  76. {
  77.     /* No in-use check */
  78.     CloseHandle(mutex->hevent) ;
  79.     mutex->hevent = NULL ; /* Just in case */
  80. }
  81.  
  82. DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
  83. {
  84.     /* Assume that the thread waits successfully */
  85.     DWORD ret ;
  86.  
  87.     /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
  88.     if (!wait)
  89.     {
  90.         if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1)
  91.             return WAIT_TIMEOUT ;
  92.         ret = WAIT_OBJECT_0 ;
  93.     }
  94.     else
  95.         ret = InterlockedIncrement(&mutex->owned) ?
  96.             /* Some thread owns the mutex, let's wait... */
  97.             WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
  98.  
  99.     mutex->thread_id = GetCurrentThreadId() ; /* We own it */
  100.     return ret ;
  101. }
  102.  
  103. BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex)
  104. {
  105.     /* We don't own the mutex */
  106.     mutex->thread_id = 0 ;
  107.     return
  108.         InterlockedDecrement(&mutex->owned) < 0 ||
  109.         SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
  110. }
  111.  
  112. PNRMUTEX AllocNonRecursiveMutex()
  113. {
  114.     PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
  115.     if (mutex && !InitializeNonRecursiveMutex(mutex))
  116.     {
  117.         free(mutex) ;
  118.         mutex = NULL ;
  119.     }
  120.     return mutex ;
  121. }
  122.  
  123. void FreeNonRecursiveMutex(PNRMUTEX mutex)
  124. {
  125.     if (mutex)
  126.     {
  127.         DeleteNonRecursiveMutex(mutex) ;
  128.         free(mutex) ;
  129.     }
  130. }
  131.  
  132. long PyThread_get_thread_ident(void);
  133.  
  134. /*
  135.  * Change all headers to pure ANSI as no one will use K&R style on an
  136.  * NT
  137.  */
  138.  
  139. /*
  140.  * Initialization of the C package, should not be needed.
  141.  */
  142. static void PyThread__init_thread(void)
  143. {
  144. }
  145.  
  146. /*
  147.  * Thread support.
  148.  */
  149. int PyThread_start_new_thread(void (*func)(void *), void *arg)
  150. {
  151.     long rv;
  152.     int success = 0;
  153.  
  154.     dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident()));
  155.     if (!initialized)
  156.         PyThread_init_thread();
  157.  
  158.     rv = _beginthread(func, 0, arg); /* use default stack size */
  159.  
  160.     if (rv != -1) {
  161.         success = 1;
  162.         dprintf(("%ld: PyThread_start_new_thread succeeded: %ld\n", PyThread_get_thread_ident(), rv));
  163.     }
  164.  
  165.     return success;
  166. }
  167.  
  168. /*
  169.  * Return the thread Id instead of an handle. The Id is said to uniquely identify the
  170.  * thread in the system
  171.  */
  172. long PyThread_get_thread_ident(void)
  173. {
  174.     if (!initialized)
  175.         PyThread_init_thread();
  176.  
  177.     return GetCurrentThreadId();
  178. }
  179.  
  180. static void do_PyThread_exit_thread(int no_cleanup)
  181. {
  182.     dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
  183.     if (!initialized)
  184.         if (no_cleanup)
  185.             _exit(0);
  186.         else
  187.             exit(0);
  188.     _endthread();
  189. }
  190.  
  191. void PyThread_exit_thread(void)
  192. {
  193.     do_PyThread_exit_thread(0);
  194. }
  195.  
  196. void PyThread__exit_thread(void)
  197. {
  198.     do_PyThread_exit_thread(1);
  199. }
  200.  
  201. #ifndef NO_EXIT_PROG
  202. static void do_PyThread_exit_prog(int status, int no_cleanup)
  203. {
  204.     dprintf(("PyThread_exit_prog(%d) called\n", status));
  205.     if (!initialized)
  206.         if (no_cleanup)
  207.             _exit(status);
  208.         else
  209.             exit(status);
  210. }
  211.  
  212. void PyThread_exit_prog(int status)
  213. {
  214.     do_PyThread_exit_prog(status, 0);
  215. }
  216.  
  217. void PyThread__exit_prog _P1(int status)
  218. {
  219.     do_PyThread_exit_prog(status, 1);
  220. }
  221. #endif /* NO_EXIT_PROG */
  222.  
  223. /*
  224.  * Lock support. It has too be implemented as semaphores.
  225.  * I [Dag] tried to implement it with mutex but I could find a way to
  226.  * tell whether a thread already own the lock or not.
  227.  */
  228. PyThread_type_lock PyThread_allocate_lock(void)
  229. {
  230.     PNRMUTEX aLock;
  231.  
  232.     dprintf(("PyThread_allocate_lock called\n"));
  233.     if (!initialized)
  234.         PyThread_init_thread();
  235.  
  236.     aLock = AllocNonRecursiveMutex() ;
  237.  
  238.     dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock));
  239.  
  240.     return (PyThread_type_lock) aLock;
  241. }
  242.  
  243. void PyThread_free_lock(PyThread_type_lock aLock)
  244. {
  245.     dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
  246.  
  247.     FreeNonRecursiveMutex(aLock) ;
  248. }
  249.  
  250. /*
  251.  * Return 1 on success if the lock was acquired
  252.  *
  253.  * and 0 if the lock was not acquired. This means a 0 is returned
  254.  * if the lock has already been acquired by this thread!
  255.  */
  256. int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
  257. {
  258.     int success ;
  259.  
  260.     dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(),(long)aLock, waitflag));
  261.  
  262.     success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ;
  263.  
  264.     dprintf(("%ld: PyThread_acquire_lock(%lx, %d) -> %d\n", PyThread_get_thread_ident(),(long)aLock, waitflag, success));
  265.  
  266.     return success;
  267. }
  268.  
  269. void PyThread_release_lock(PyThread_type_lock aLock)
  270. {
  271.     dprintf(("%ld: PyThread_release_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
  272.  
  273.     if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
  274.         dprintf(("%ld: Could not PyThread_release_lock(%lx) error: %l\n", PyThread_get_thread_ident(), (long)aLock, GetLastError()));
  275. }
  276.  
  277. /*
  278.  * Semaphore support.
  279.  */
  280. PyThread_type_sema PyThread_allocate_sema(int value)
  281. {
  282.     HANDLE aSemaphore;
  283.  
  284.     dprintf(("%ld: PyThread_allocate_sema called\n", PyThread_get_thread_ident()));
  285.     if (!initialized)
  286.         PyThread_init_thread();
  287.  
  288.     aSemaphore = CreateSemaphore( NULL,           /* Security attributes          */
  289.                                   value,          /* Initial value                */
  290.                                   INT_MAX,        /* Maximum value                */
  291.                                   NULL);          /* Name of semaphore            */
  292.  
  293.     dprintf(("%ld: PyThread_allocate_sema() -> %lx\n", PyThread_get_thread_ident(), (long)aSemaphore));
  294.  
  295.     return (PyThread_type_sema) aSemaphore;
  296. }
  297.  
  298. void PyThread_free_sema(PyThread_type_sema aSemaphore)
  299. {
  300.     dprintf(("%ld: PyThread_free_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
  301.  
  302.     CloseHandle((HANDLE) aSemaphore);
  303. }
  304.  
  305. /*
  306.   XXX must do something about waitflag
  307.  */
  308. int PyThread_down_sema(PyThread_type_sema aSemaphore, int waitflag)
  309. {
  310.     DWORD waitResult;
  311.  
  312.     dprintf(("%ld: PyThread_down_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
  313.  
  314.     waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE);
  315.  
  316.     dprintf(("%ld: PyThread_down_sema(%lx) return: %l\n", PyThread_get_thread_ident(),(long) aSemaphore, waitResult));
  317.     return 0;
  318. }
  319.  
  320. void PyThread_up_sema(PyThread_type_sema aSemaphore)
  321. {
  322.     ReleaseSemaphore(
  323.                 (HANDLE) aSemaphore,            /* Handle of semaphore                          */
  324.                 1,                              /* increment count by one                       */
  325.                 NULL);                          /* not interested in previous count             */
  326.                                                 
  327.     dprintf(("%ld: PyThread_up_sema(%lx)\n", PyThread_get_thread_ident(), (long)aSemaphore));
  328. }
  329.